<!DOCTYPE html>
<html lang="en">

    <head><title>Springboot实现websocket双方通信 &ndash; UxiaoTag的博客</title>
<meta name="description" content="一个蒟蒻无比的萌新.">

<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8"/>



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" integrity="sha512-1sCRPdkRXhBV2PBLUdRb4tMg1w2YPf37qatUFeS7zlBy7jJI8Lf4VHwWfZZfpXtYSLy85pkm9GaYVYMfw5BC1A==" crossorigin="anonymous" />


<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/academicons/1.9.1/css/academicons.min.css" integrity="sha512-b1ASx0WHgVFL5ZQhTgiPWX+68KjS38Jk87jg7pe+qC7q9YkEtFq0z7xCglv7qGIs/68d3mAp+StfC8WKC5SSAg==" crossorigin="anonymous" />


<link rel="stylesheet" href="https://juruoxiao.gitee.io/linux_work/css/palettes/base16-dark.css">
<link rel="stylesheet" href="https://juruoxiao.gitee.io/linux_work/css/risotto.css">
<link rel="stylesheet" href="https://juruoxiao.gitee.io/linux_work/css/custom.css">
</head>

    <body>
        <div class="page">

            <header class="page__header"><h1 class="page__logo"><a href="https://juruoxiao.gitee.io/linux_work" class="page__logo-inner">UxiaoTag的博客</a></h1>
<nav class="page__nav main-nav">
    <ul>
    
    
    <li class="main-nav__item"><a class="nav-main-item" href="https://juruoxiao.gitee.io/linux_work/about/" title="">About</a></li>
    
    <li class="main-nav__item"><a class="nav-main-item active" href="https://juruoxiao.gitee.io/linux_work/post/" title="Posts">Posts</a></li>
    
    </ul>
</nav>

</header>

            <section class="page__body">
    <header class="content__header">
        <h1>Springboot实现websocket双方通信</h1>
    </header>
    <div class="content__body">
        <p>通过spring作为服务端，html写的js作为客户端(部署在nginx中)</p>
<h2 id="什么是websocket">什么是websocket</h2>
<p>​	<strong>WebSocket</strong>是一种在单个<a href="https://baike.baidu.com/item/TCP?fromModule=lemma_inlink">TCP</a>连接上进行<a href="https://baike.baidu.com/item/%E5%85%A8%E5%8F%8C%E5%B7%A5?fromModule=lemma_inlink">全双工</a>通信的协议。WebSocket通信协议于2011年被<a href="https://baike.baidu.com/item/IETF?fromModule=lemma_inlink">IETF</a>定为标准RFC 6455，并由RFC7936补充规范。WebSocket API也被<a href="https://baike.baidu.com/item/W3C?fromModule=lemma_inlink">W3C</a>定为标准。</p>
<p>​	WebSocket使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。在WebSocket API中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接，并进行双向数据传输。</p>
<h2 id="需要">需要</h2>
<p>•java8</p>
<p>•maven</p>
<p>•Springboot2.7.4(这里有一个坑，springboot推出3.0之后，不再支持java8，需要java17)</p>
<p>•WebSocket模块</p>
<h2 id="websocket服务端实现">WebSocket服务端实现</h2>
<p>（本代码来自各个博客，集百家之长）</p>
<p>首先，springboot项目重中之重需要添加websocket</p>
<p><em>pom.xml</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>            
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.boot<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>spring-boot-starter-websocket<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><h4 id="websockethandler">WebSocketHandler</h4>
<p>WebSocketHandler是一个处理 WebSocket 消息和生命周期事件的接口(需要重写)。如下WebSocketHandler的源码（注释是其他大佬标出来的）</p>
<p><em>WebSocketHandler.java</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">WebSocketHandler</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    * 建立连接后触发的回调
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    */</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterConnectionEstablished</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    * 收到消息时触发的回调
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    */</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handleMessage</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> WebSocketMessage<span style="color:#f92672">&lt;?&gt;</span> message<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    * 传输消息出错时触发的回调
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    */</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handleTransportError</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> Throwable exception<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    * 断开连接后触发的回调
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    */</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterConnectionClosed</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> CloseStatus closeStatus<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    * 是否处理分片消息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    */</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">supportsPartialMessages</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>同理，根据上面的内容我们可以写一份属于自己的WebSocketHandler，如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WebsocketHandler</span> <span style="color:#66d9ef">implements</span> WebSocketHandler <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> Map<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> WebSocketSession<span style="color:#f92672">&gt;</span> SESSIONS <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ConcurrentHashMap<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterConnectionEstablished</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;连接成功&#34;</span> <span style="color:#f92672">+</span> session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">(),</span> session<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;当前在线人数：&#34;</span> <span style="color:#f92672">+</span> SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">size</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handleMessage</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> WebSocketMessage<span style="color:#f92672">&lt;?&gt;</span> message<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;接收消息&#34;</span> <span style="color:#f92672">+</span> session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        String msg <span style="color:#f92672">=</span> message<span style="color:#f92672">.</span><span style="color:#a6e22e">getPayload</span><span style="color:#f92672">().</span><span style="color:#a6e22e">toString</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//        session.sendMessage(message);
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        sendMessageToAllUsers<span style="color:#f92672">(</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;:&#34;</span> <span style="color:#f92672">+</span> msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">handleTransportError</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> Throwable exception<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;连接出错&#34;</span> <span style="color:#f92672">+</span> session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">isOpen</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">remove</span><span style="color:#f92672">(</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>            session<span style="color:#f92672">.</span><span style="color:#a6e22e">close</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterConnectionClosed</span><span style="color:#f92672">(</span>WebSocketSession session<span style="color:#f92672">,</span> CloseStatus closeStatus<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;关闭连接&#34;</span> <span style="color:#f92672">+</span> session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(!</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">isOpen</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">remove</span><span style="color:#f92672">(</span>session<span style="color:#f92672">.</span><span style="color:#a6e22e">getId</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;当前在线人数：&#34;</span> <span style="color:#f92672">+</span> SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">size</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">supportsPartialMessages</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * sendMessageToUser:发给指定用户
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sendMessageToUser</span><span style="color:#f92672">(</span>String userId<span style="color:#f92672">,</span> String contents<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        WebSocketSession session <span style="color:#f92672">=</span> SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>session <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">&amp;&amp;</span> session<span style="color:#f92672">.</span><span style="color:#a6e22e">isOpen</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                TextMessage message <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TextMessage<span style="color:#f92672">(</span>contents<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                session<span style="color:#f92672">.</span><span style="color:#a6e22e">sendMessage</span><span style="color:#f92672">(</span>message<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>IOException e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * sendMessageToAllUsers:发给所有的用户
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sendMessageToAllUsers</span><span style="color:#f92672">(</span>String contents<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Set<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> userIds <span style="color:#f92672">=</span> SESSIONS<span style="color:#f92672">.</span><span style="color:#a6e22e">keySet</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span>String userId <span style="color:#f92672">:</span> userIds<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">sendMessageToUser</span><span style="color:#f92672">(</span>userId<span style="color:#f92672">,</span> contents<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h4 id="websocketinterceptor">WebsocketInterceptor</h4>
<p>这个拦截器的实现主要是通过实现<em>HandshakeInterceptor</em>这个类，该类只需要实现前置拦截和后置拦截，源码如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Source code recreated from a .class file by IntelliJ IDEA
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// (powered by FernFlower decompiler)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">HandshakeInterceptor</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">beforeHandshake</span><span style="color:#f92672">(</span>ServerHttpRequest request<span style="color:#f92672">,</span> ServerHttpResponse response<span style="color:#f92672">,</span> WebSocketHandler wsHandler<span style="color:#f92672">,</span> Map<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> Object<span style="color:#f92672">&gt;</span> attributes<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterHandshake</span><span style="color:#f92672">(</span>ServerHttpRequest request<span style="color:#f92672">,</span> ServerHttpResponse response<span style="color:#f92672">,</span> WebSocketHandler wsHandler<span style="color:#f92672">,</span> <span style="color:#a6e22e">@Nullable</span> Exception exception<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>实现也很简单：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WebsocketInterceptor</span> <span style="color:#66d9ef">implements</span> HandshakeInterceptor <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">beforeHandshake</span><span style="color:#f92672">(</span>ServerHttpRequest request<span style="color:#f92672">,</span> ServerHttpResponse response<span style="color:#f92672">,</span> WebSocketHandler wsHandler<span style="color:#f92672">,</span> Map<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> Object<span style="color:#f92672">&gt;</span> attributes<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;前置拦截&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">afterHandshake</span><span style="color:#f92672">(</span>ServerHttpRequest request<span style="color:#f92672">,</span> ServerHttpResponse response<span style="color:#f92672">,</span> WebSocketHandler wsHandler<span style="color:#f92672">,</span> Exception exception<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;后置拦截&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h4 id="websocketconfig">WebSocketConfig</h4>
<p>实现这个东西我上网查了一下，有xml实现或者实现<em>WebSocketConfigurer</em>，我选择的方法是是实现WebSocketConfigurer。主要是实现注册的。以下是源码：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">WebSocketConfigurer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">registerWebSocketHandlers</span><span style="color:#f92672">(</span>WebSocketHandlerRegistry registry<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>实现如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@Configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableWebSocket</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WebSocketConfig</span> <span style="color:#66d9ef">implements</span> WebSocketConfigurer <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> WebsocketInterceptor websocketInterceptor<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Autowired</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> WebsocketHandler webSocketHandler<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">registerWebSocketHandlers</span><span style="color:#f92672">(</span>WebSocketHandlerRegistry registry<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    registry<span style="color:#f92672">.</span><span style="color:#a6e22e">addHandler</span><span style="color:#f92672">(</span>webSocketHandler<span style="color:#f92672">,</span><span style="color:#e6db74">&#34;ws&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">setAllowedOrigins</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;*&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">addInterceptors</span><span style="color:#f92672">(</span>websocketInterceptor<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>也可以直接这样生成一个放在addHandler里面，就不演示了</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>    <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> WebSocketHandler <span style="color:#a6e22e">myHandler</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> MyHandler<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="websocket客户端">WebSocket客户端</h2>
<p>客户端其实没有很讲究，无非就是看看自己支持websocket或否，支持的话就创建webSocket,写相关回调的方法，读取message返回到页面中。客户端本体是一个页面，我通过nginx将其部署在服务器上（使用了docker）</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><span style="color:#75715e">&lt;!DOCTYPE html&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">html</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">head</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">meta</span> <span style="color:#a6e22e">charset</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;UTF-8&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">title</span>&gt;My WebSocket Test&lt;/<span style="color:#f92672">title</span>&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!-- 最新版本的 Bootstrap 核心 CSS 文件 --&gt;</span>
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;stylesheet&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css&#34;</span> <span style="color:#a6e22e">integrity</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu&#34;</span> <span style="color:#a6e22e">crossorigin</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anonymous&#34;</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!-- 可选的 Bootstrap 主题文件（一般不用引入） --&gt;</span>
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">link</span> <span style="color:#a6e22e">rel</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;stylesheet&#34;</span> <span style="color:#a6e22e">href</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css&#34;</span> <span style="color:#a6e22e">integrity</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ&#34;</span> <span style="color:#a6e22e">crossorigin</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anonymous&#34;</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">&lt;!-- 最新的 Bootstrap 核心 JavaScript 文件 --&gt;</span>
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js&#34;</span> <span style="color:#a6e22e">integrity</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd&#34;</span> <span style="color:#a6e22e">crossorigin</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;anonymous&#34;</span>&gt;&lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">head</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">body</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Welcome&lt;<span style="color:#f92672">br</span>/&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;message&#34;</span>&gt;&lt;/<span style="color:#f92672">div</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">input</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text&#34;</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text&#34;</span> /&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;btn btn-primary&#34;</span> <span style="color:#a6e22e">onclick</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;send()&#34;</span>&gt;Send&lt;/<span style="color:#f92672">button</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;btn btn-danger&#34;</span><span style="color:#a6e22e">onclick</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;closeWebSocket()&#34;</span>&gt;Close&lt;/<span style="color:#f92672">button</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">body</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/javascript&#34;</span>&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">websocket</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//判断当前浏览器是否支持WebSocket
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span>(<span style="color:#e6db74">&#39;WebSocket&#39;</span> <span style="color:#66d9ef">in</span> window){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">websocket</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">WebSocket</span>(<span style="color:#e6db74">&#34;ws://localhost:8001/ws&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">else</span>{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">alert</span>(<span style="color:#e6db74">&#39;Not support websocket&#39;</span>)
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//连接发生错误的回调方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">onerror</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">setMessageInnerHTML</span>(<span style="color:#e6db74">&#34;error&#34;</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//连接成功建立的回调方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">onopen</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(<span style="color:#a6e22e">event</span>){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">setMessageInnerHTML</span>(<span style="color:#e6db74">&#34;open&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//接收到消息的回调方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">onmessage</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(<span style="color:#a6e22e">event</span>){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">setMessageInnerHTML</span>(<span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">data</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//连接关闭的回调方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">onclose</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">setMessageInnerHTML</span>(<span style="color:#e6db74">&#34;close&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    window.<span style="color:#a6e22e">onbeforeunload</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">close</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//将消息显示在网页上
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">setMessageInnerHTML</span>(<span style="color:#a6e22e">innerHTML</span>){
</span></span><span style="display:flex;"><span>        document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;message&#39;</span>).<span style="color:#a6e22e">innerHTML</span> <span style="color:#f92672">+=</span> <span style="color:#a6e22e">innerHTML</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#39;&lt;br/&gt;&#39;</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//关闭连接
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">closeWebSocket</span>(){
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">close</span>();
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//发送消息
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">send</span>(){
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">message</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;text&#39;</span>).<span style="color:#a6e22e">value</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">websocket</span>.<span style="color:#a6e22e">send</span>(<span style="color:#a6e22e">message</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">message</span>.<span style="color:#a6e22e">value</span>(<span style="color:#e6db74">&#34;&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">html</span>&gt;
</span></span></code></pre></div><h2 id="关于使用docket部署">关于使用docket部署</h2>
<p>本次使用docker部署服务端和客户端都比较简单。先说服务端，本次服务端是用java8写的。</p>
<h4 id="服务端">服务端</h4>
<p>所以现在在docker中获取java8镜像：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker pull java:8
</span></span></code></pre></div><p>然后对已有文件进行打包，用mvean:</p>
<pre tabindex="0"><code>mvn clean package
</code></pre><p>打包完后，包会存在target中(有人说是在target/lib，一般都在里面找找有的),然后写一份dockerFile就可以实现了：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> java:8</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">VOLUME</span><span style="color:#e6db74"> /tmp/tomcat</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ADD</span> webSocket.jar webSocket.jar<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENTRYPOINT</span> [<span style="color:#e6db74">&#34;java&#34;</span>,<span style="color:#e6db74">&#34;-Djava.security.egd=file:/dev/./urandom&#34;</span>,<span style="color:#e6db74">&#34;-jar&#34;</span>,<span style="color:#e6db74">&#34;/webSocket.jar&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>最后执行：</p>
<pre tabindex="0"><code>mvn docker:build
</code></pre><p>执行完查看镜像：</p>
<pre tabindex="0"><code>docker image
</code></pre><p>运行：</p>
<pre tabindex="0"><code>docker run --name 实例名字 -p 8001:8001（我这边8001）
</code></pre><h4 id="客户端">客户端</h4>
<p>客户端主要是通过nginx来部署的，docker下载nginx</p>
<pre tabindex="0"><code>docker pull nginx:latest
</code></pre><p>运行镜像</p>
<pre tabindex="0"><code>docker run --name 实例名字 -p 8002:80（我这边8002）
</code></pre><p>后续有俩种做法把网页传进去，一种是docker cp，还有一种在运行中加入-v参数将docker数据与本地数据对应。如何使用取决于自己。</p>
<p><em>虽然代码来自别人，但是亲手试验过感觉还是很不错的。</em></p>
    </div>
    <footer class="content__footer"></footer>

            </section>

            <section class="page__aside">
                <div class="aside__about">
<div class="aside__about">
    <img class="about__logo" src="https://juruoxiao.gitee.io/linux_work/images/rice.svg" alt="Logo">
<h1 class="about__title">UxiaoTag</h1>
<p class="about__description">一个蒟蒻无比的萌新.</p>
</div>


<ul class="aside__social-links">
    
    <li>
        <a href="https://github.com/q2516631454" rel="me" aria-label="GitHub" title="GitHub"><i class="fa-brands fa-github" aria-hidden="true"></i></a>&nbsp;
    </li>
    
    <li>
        <a href="mailto:2516631454@qq.com" rel="me" aria-label="Email" title="Email"><i class="fa-solid fa-envelope" aria-hidden="true"></i></a>&nbsp;
    </li>
    
</ul>





<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/sakana-widget@2.5.0/lib/sakana.min.css"
/>
<div id="sakana-widget"></div>
<script>
  function initSakanaWidget() {
    const takina = SakanaWidget.getCharacter('takina');
    takina.initialState = {
      ...takina.initialState,
      i: 0.01,
      d: 1,
    };
    SakanaWidget.registerCharacter('takina-slow', takina);
    new SakanaWidget({ character: 'takina-slow',controls:false}).mount('#sakana-widget');
  }
</script>
<script
  async
  onload="initSakanaWidget()"
  src="https://cdn.jsdelivr.net/npm/sakana-widget@2.5.0/lib/sakana.min.js"
></script>
</div>
                <hr>
                <div class="aside__content">
    <p>Springboot实现websocket双方通信,通过Springboot作为服务端，html(js调用websocket)作为客户端(部署在nginx中)</p>
    
        <p>
            By UxiaoTag, 
            2022-12-05
        </p>
    

                </div>
            </section>

            <footer class="page__footer"><p>
    
    
    
    
    
    
      
    
      
    
    
    
</p>
<br /><br />
<p class="copyright">© 2021–2022 <a href="https://gitee.com/juruoxiao/linux_work">UxiaoTag</a></p>
<p class="advertisement">Powered by <a href="https://gohugo.io/">hugo</a> and <a href="https://github.com/joeroe/risotto">risotto</a>.</p>
</footer>

        </div>
    </body>

</html>
